#pragma once

#include <string>

#include "type_traits.hpp"

namespace bzbee
{
    template< typename T >
    typename std::enable_if< std::is_integral< std::decay_t<T> >::value
        && std::is_signed< std::decay_t<T> >::value
        && (sizeof(T) <= sizeof(std::int32_t))
        , T >::type
        fromString(const char* str)
    {
        T t;
        try
        {
            t = static_cast<T>(std::stol(str));
        }
        catch (std::exception& e)
        {
            (void)e;
            return T();
        }
        return t;
    }

    template< typename T >
    typename std::enable_if< std::is_integral< std::decay_t<T> >::value
        && std::is_signed< std::decay_t<T> >::value
        && (sizeof(T) > sizeof(std::int32_t) && sizeof(T) <= sizeof(int64_t))
        , T >::type
        fromString(const char* str)
    {
        T t;
        try
        {
            t = static_cast<T>(std::stoll(str));
        }
        catch (std::exception& e)
        {
            (void)e;
            return T();
        }
        return t;
    }

    template< typename T >
    typename std::enable_if< std::is_integral< std::decay_t<T> >::value
        && !std::is_signed< std::decay_t<T> >::value
        && (sizeof(T) <= sizeof(uint32_t))
        , T >::type
        fromString(const char* str)
    {
        T t;
        try
        {
            t = static_cast<T>(std::stoul(str));
        }
        catch (std::exception& e)
        {
            (void)e;
            return T();
        }
        return t;
    }

    template< typename T >
    typename std::enable_if< std::is_integral< std::decay_t<T> >::value
        && !std::is_signed< std::decay_t<T> >::value
        && (sizeof(T) > sizeof(uint32_t) && sizeof(T) <= sizeof(uint64_t))
        , T >::type
        fromString(const char* str)
    {
        T t;
        try
        {
            t = static_cast<T>(std::stoull(str));
        }
        catch (std::exception& e)
        {
            (void)e;
            return T();
        }
        return t;
    }

    template< typename T >
    typename std::enable_if< std::is_floating_point< std::decay_t<T> >::value
        , T >::type
        fromString(const char* str)
    {
        T t;
        try
        {
            t = static_cast<T>(std::stod(str));
        }
        catch (std::exception& e)
        {
            (void)e;
            return T();
        }
        return t;
    }

    template< typename T >
    typename std::enable_if< std::is_integral< std::decay_t<T> >::value
        && std::is_signed< std::decay_t<T> >::value
        && (sizeof(T) <= sizeof(int32_t))
        , T >::type
        fromString(const std::string& str)
    {
        T t;
        try
        {
            t = static_cast<T>(std::stol(str));
        }
        catch (std::exception& e)
        {
            (void)e;
            return T();
        }
        return t;
    }

    template< typename T >
    typename std::enable_if< std::is_integral< std::decay_t<T> >::value
        && std::is_signed< std::decay_t<T> >::value
        && (sizeof(T) > sizeof(int32_t) && sizeof(T) <= sizeof(int64_t))
        , T >::type
        fromString(const std::string& str)
    {
        T t;
        try
        {
            t = static_cast<T>(std::stoll(str));
        }
        catch (std::exception& e)
        {
            (void)e;
            return T();
        }
        return t;
    }

    template< typename T >
    typename std::enable_if< std::is_integral< std::decay_t<T> >::value
        && !std::is_signed< std::decay_t<T> >::value
        && (sizeof(T) <= sizeof(uint32_t))
        , T >::type
        fromString(const std::string& str)
    {
        T t;
        try
        {
            t = static_cast<T>(std::stoul(str));
        }
        catch (std::exception& e)
        {
            (void)e;
            return T();
        }
        return t;
    }

    template< typename T >
    typename std::enable_if< std::is_integral< std::decay_t<T> >::value
        && !std::is_signed< std::decay_t<T> >::value
        && (sizeof(T) > sizeof(uint32_t) && sizeof(T) <= sizeof(uint64_t))
        , T >::type
        fromString(const std::string& str)
    {
        T t;
        try
        {
            t = static_cast<T>(std::stoull(str));
        }
        catch (std::exception& e)
        {
            (void)e;
            return T();
        }
        return t;
    }

    template< typename T >
    typename std::enable_if< std::is_floating_point< std::decay_t<T> >::value
        , T >::type
        fromString(const std::string& str)
    {
        T t;
        try
        {
            t = static_cast<T>(std::stod(str));
        }
        catch (std::exception& e)
        {
            (void)e;
            return T();
        }
        return t;
    }

} // !namespace bzbee
